package com.cygsunri.consumption.task;

import com.alibaba.fastjson.JSONObject;
import com.cygsunri.consumption.entity.Branch;
import com.cygsunri.consumption.entity.response.ElectricityMeter;
import com.cygsunri.consumption.entity.response.HGResponse;
import com.cygsunri.consumption.entity.response.WaterMete;
import com.cygsunri.consumption.service.BranchService;
import com.cygsunri.consumption.transport.AsmxTrans;
import com.cygsunri.measurement.calculate.AbstractComplexEndureCalculateService;
import com.cygsunri.measurement.entity.MeasurementValue;
import com.cygsunri.scada.base.BasePSR;
import com.cygsunri.scada.service.ScadaMeasurementService;
import com.cygsunri.template.entity.psr.DeviceTemplate;
import com.cygsunri.template.entity.psr.DeviceTemplateData;
import com.cygsunri.template.service.DeviceTemplateDataService;
import com.cygsunri.template.service.PSRTemplateMappingService;
import com.cygsunri.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 获取汉光支路数据，详见接口文档 docs/HKST数据接口.docx
 */
@Component
@Slf4j
@ConditionalOnProperty(prefix = "task.consumption.meter", name = "open", havingValue = "true")
@PropertySource(name = "application.yml", value = {"classpath:application.yml"}, ignoreResourceNotFound = false, encoding = "UTF-8")
public class MeterDataTask extends AbstractComplexEndureCalculateService {

    @Autowired
    private AsmxTrans asmxTrans;
    @Autowired
    private PSRTemplateMappingService psrTemplateMappingService;
    @Autowired
    private BranchService branchService;
    @Autowired
    private ScadaMeasurementService scadaMeasurementService;
    @Autowired
    private DeviceTemplateDataService deviceTemplateDataService;

    private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");

    @Scheduled(cron = "${task.consumption.meter.cron}")
    private void getMeterData() {
        long a = System.currentTimeMillis();
        //todo 建筑和类型号先写死，PageIndex和PageSize只要比现场表数量多即可
        String[] types = {"002001", "002002", "002006"};

        for (String type : types) {
            try {
                Object[] p = {"", "12", type, "1", "50"};
                String result = asmxTrans.getBuildingMeterCurrentData(p);
                if (result == null) {
                    setAllMeterStatus(type);
                    continue;
                }
                HGResponse hgResponse = JSONObject.parseObject(result, HGResponse.class);
                if ("-1".equals(hgResponse.getResult())) {
                    log.warn("汉光数据接收失败，类型：{}，result：{}", type, hgResponse.getResult());
                    continue;
                }

                if ("002001".equals(type)) {
                    electricityMeter(hgResponse);
                } else {
                    //压力表和水表json结构一致
                    waterMeter(hgResponse);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("表计数据处理耗时:{}ms", System.currentTimeMillis() - a);
    }

    /**
     * 电表数据分析
     */
    private void electricityMeter(HGResponse hgResponse) {
        for (Object object : hgResponse.getJbody()) {
            try {
                ElectricityMeter electricityMeter = JSONObject.parseObject(JSONObject.toJSONString(object), ElectricityMeter.class);
                String virtualDevID = electricityMeter.getVirtualDevID();
                Branch branch = branchService.getBranchById(virtualDevID);
                if (branch == null) continue;
                DeviceTemplate deviceTemplate = psrTemplateMappingService.getDeviceTemplateByMapping(branch.getPsrID());
                if (deviceTemplate == null) continue;
                reflexObject(deviceTemplate, branch, electricityMeter);
                setMeterStatus(branch, electricityMeter.getUpdateTime());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 水表、压力表数据分析
     */
    private void waterMeter(HGResponse hgResponse) {
        for (Object object : hgResponse.getJbody()) {
            try {
                WaterMete waterMete = JSONObject.parseObject(JSONObject.toJSONString(object), WaterMete.class);
                String virtualDevID = waterMete.getVirtualDevID();
                Branch branch = branchService.getBranchById(virtualDevID);
                if (branch == null) continue;
                DeviceTemplate deviceTemplate = psrTemplateMappingService.getDeviceTemplateByMapping(branch.getPsrID());
                if (deviceTemplate == null) continue;
                reflexObject(deviceTemplate, branch, waterMete);
                setMeterStatus(branch, waterMete.getUpdateTime());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 通过反射获取数据
     */
    private void reflexObject(DeviceTemplate deviceTemplate, Branch branch, Object o) {
        List<DeviceTemplateData> deviceTemplateDatas = deviceTemplateDataService.getDeviceTemplateDataListByDeviceTemplateId(deviceTemplate.getId());
        for (DeviceTemplateData data : deviceTemplateDatas) {
            try {
                String measureId = scadaMeasurementService.getMeasurementID(branch.getPsrID(), data);
                String name = data.getName();
                //todo 反射对电表和水表name特殊处理
                if ("Electricity".equals(name)) {
                    name = "Eall";
                } else if ("Water".equals(name) || "Pressure".equals(name)) {
                    name = "Value";
                }
                name = name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
                Method m = o.getClass().getMethod("get" + name);
                Object value = m.invoke(o);
                if (value == null) continue;
                this.saveMean(measureId, (Double) value, DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Normal.getKey());
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 判断表数据是否超时
     */
    private void setMeterStatus(Branch branch, String updateTime) {
        try {
            int timeLength = 23;
            if (updateTime.length() != timeLength) {
                updateTime = updateTime + String.format("%1$0" + (timeLength - updateTime.length()) + "d", 0);
            }
            LocalDateTime localDateTime = LocalDateTime.parse(updateTime, dtf);
            BasePSR basePSR = new BasePSR().setId(branch.getPsrID()).setName(branch.getName());
            if (Duration.between(localDateTime, LocalDateTime.now()).toMinutes() > (60 * 24 * 2)) {
                setDeviceStatus(basePSR, "COMMUNICATION_FAULT");
            } else {
                setDeviceStatus(basePSR, "RUNNING");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置所有表通讯状态
     */
    private void setAllMeterStatus(String type) {
        String energySort;
        switch (type) {
            case "002001":
                energySort = "Electricity";
                break;
            case "002002":
                energySort = "Water";
                break;
            case "002006":
                energySort = "Pressure";
                break;
            default:
                return;
        }
        List<Branch> branchList = branchService.getBranchesByEnergySort(energySort);
        branchList.forEach(branch -> {
            BasePSR basePSR = new BasePSR().setId(branch.getPsrID()).setName(branch.getName());
            setDeviceStatus(basePSR, "COMMUNICATION_FAULT");
        });
    }
}